Entity 与 EntityData

Entity 与 EntityData

entity

Entity 作成(在 v3 环境中新规,然后拷贝到 v4)

⚡ C:\gf4\其他\代码\entity 作成
[entity作成](file:///C:%5Cgf4%5C其他%5C代码%5Centity作成)

类注解

❗唯一键只有一个字段时,可以写成变量注解,无需写成类注解

// 唯一键有多个字段
@Entity  
@Table(name = "groupware_message_recipient", schema = PersistenceConstants.DEFAULT_SCHEMA, uniqueConstraints = {  
        @UniqueConstraint(columnNames = { "groupware_message_entityid", "destination_user_entityid" }),  
        @UniqueConstraint(columnNames = { "groupware_message_entityid", "groupware_board_category_entityid" }) })
 
// 唯一键只有一个字段
@Column(name = "center_id", nullable = false, unique = true)
private String centerId;

变量注解

@Column(nullable = false, name = "id", columnDefinition = "numeric(8)", length = 255)  
@Basic(optional = false)
private long id;
式样书变量类型 Java 代码类型 特定注解 数据库类型 (default) 备注
text String @Lob text
枚举 枚举 @Enumerated(EnumType.STRING) varchar(255)
timestamp LocalDateTime or Date @Temporal(TemporalType.TIMESTAMP) timestamp
date LocalDate or Date @Temporal(TemporalType.DATE) date
bigserial Long bigserial
bigint long int8
integer int or Integer int4
varchar、character String varchar(255)
numeric BigDecimal numeric
关联的其他表(bigint) entity ManyToOne OneToMany int8
特殊枚举 PrefectureCode @Enumerated(EnumType.ORDINAL) int2 参照 PrefectureCode
貌似时将枚举型变成了顺序数字
time Date or LocalDate @Temporal(TemporalType.TIME) time 14:00:00
float double or Double float8
Boolean Boolean or boolean bool
UUID UUID @Column(name = "student_uuid", columnDefinition = "uuid")
@Convert("uuidConverter")
uuid
text
/**  
 * itemLabel 
 */
@Column(name = "item_label", nullable = false)  
@Lob  
private String itemLabel;
枚举
/**  
 * ConditionDistinguish 
 */
@Column(name = "condition_distinguish", nullable = false)
@Enumerated(EnumType.STRING)
private ConditionDistinguish conditionDistinguish;
timestamp
/**  
 * LocalDateTime 
 */
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "date_time", nullable = false)
private LocalDateTime dateTime;

or

private Date dateTime;
date
/**  
 * LocalDate 
 */
@Temporal(TemporalType.DATE)
@Column(name = "date", nullable = false)
private LocalDate date;

or

private Date date;
time
/**  
 * time 
 */
@Temporal(TemporalType.TIME)
@Column(name = "time", nullable = false)
private LocalDate time;

or

private Date time;
bigserial
/**  
 * entityId 
 */
@Column(name = "entity_id", nullable = false)
private Long entityId;
bigint
/**  
 * entityId 
 */
@Column(name = "entity_id", nullable = false)
private long entityId;
integer
/**  
 * entityId 
 */
@Column(name = "entity_id", nullable = false)
private int entityId;
varchar、character
/**  
 * entityId 
 */
@Column(name = "entity_id", nullable = false, length = 255)
private String entityId;
numeric
/**  
 * entityId 
 */
@Column(name = "entity_id", nullable = false)
private BigDecimal entityId;
boolean
/**  
 * bool 
 */
@Column(name = "bool", nullable = false)  
private Boolean bool;

or
 
private boolean bool;
uuid
import org.eclipse.persistence.annotations.Convert;  
import org.eclipse.persistence.annotations.Converter;

@Converter(name = "uuidConverter", converterClass = UUIDConverter.class)
public class Student extends Person {
}
/**  
 * uuid 
 */
@Column(name = "student_uuid", columnDefinition = "uuid")  
@Convert("uuidConverter")  
private UUID studentUuid;
duration
/**  
 * 結果_解答時間  
 */  
@Column(name = "result_duration", columnDefinition = "integer")  
private Duration resultDuration;

ManyToOne

Summary:JPA,关于多对一的属性,是否需要加 JoinColumn 关联表字段的总结:

  1. 如果不加 JoinColumn,关联表字段。调用脚本生成的 sql,生成的字段名,是【entity 属性名_entityid】

    例如:sibling

  2. 如果,表字段名不是【entity 属性名_entityid】,则必须加 JoinColumn,否则 jpa 不能将 entity 的属性与表字段进行映射关联。

    例如:Guardian

@ManyToOne(cascade = { CascadeType.DETACH }, fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "observation_record_entityid", nullable = false)
private ObservationRecord observationRecord;

/**
 * <p>
 * プロパティ<code>observationRecord</code>の値を取得する。
 * </p>
 *
 * @return プロパティ<code>observationRecord</code>の値
 */
@ReplicatorMapping(skip = true)
public ObservationRecord getObservationRecord() {
    return getObservationRecord_internal();
}

/**
 * <p>
 * プロパティ<code>observationRecord</code>の値を設定する。
 * </p>
 *
 * @param observationRecord プロパティ<code>observationRecord</code>に設定する値
 */
public void setObservationRecord(final ObservationRecord observationRecord) {
    final OneToManySupport<ObservationRecord, ObservationRecordCoordination> oneToManySupport = RelationSupportFactory.getInstance().getOneToManySupport(ObservationRecord.class, "coordinationList",
            ObservationRecordCoordination.class, "observationRecord");
    oneToManySupport.doSetOneSide(this, observationRecord);
}

private ObservationRecord getObservationRecord_internal() {
    return observationRecord;
}

@SuppressWarnings("unused")
private void setObservationRecord_internal(final ObservationRecord observationRecord) {
    this.observationRecord = observationRecord;
}

OneToMany

@OneToMany(mappedBy = "observationRecord", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
private List<ObservationRecordCoordination> coordinationList;

/**
 * <p>
 * プロパティ<code>coordinationList</code>の値を取得する。
 * </p>
 *
 * @return プロパティ<code>coordinationList</code>の値
 */
public List<ObservationRecordCoordination> getCoordinationList() {
    final OneToManySupport<ObservationRecord, ObservationRecordCoordination> oneToManySupport = RelationSupportFactory.getInstance().getOneToManySupport(ObservationRecord.class, "coordinationList",
            ObservationRecordCoordination.class, "observationRecord");
    return oneToManySupport.doGetManySideList(this);
}

/**
 * <p>
 * プロパティ<code>coordinationList</code>の値を設定する。
 * </p>
 *
 * @param coordinationList プロパティ<code>coordinationList</code>に設定する値
 */
public void setCoordinationList(final List<ObservationRecordCoordination> coordinationList) {
    final OneToManySupport<ObservationRecord, ObservationRecordCoordination> oneToManySupport = RelationSupportFactory.getInstance().getOneToManySupport(ObservationRecord.class, "coordinationList",
            ObservationRecordCoordination.class, "observationRecord");
    oneToManySupport.doSetManySideCollection(this, coordinationList);
}

@ReplicatorMapping(skip = true)
private List<ObservationRecordCoordination> getCoordinationList_internal() {
    return coordinationList;
}

@SuppressWarnings("unused")
private void setCoordinationList_internal(final List<ObservationRecordCoordination> coordinationList) {
    this.coordinationList = coordinationList;
}

OneToOne

@OneToOne(optional = false, fetch = FetchType.LAZY)  
@JoinColumn(nullable = false)  
private WeeklyPlanParticularLesson particularLesson;
@OneToOne(mappedBy = "particularLesson", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true) 
private TeachPlanSchool schoolPlan;

addToStringFields

@Override
protected void addToStringFields(final ToStringBuilder builder) {
    super.addToStringFields(builder);
    builder.append("answerRequestNo", getAnswerRequestNo());
    builder.appendLazy("questionnaireItemRegionGroup");
    builder.appendLazy("schoolMembership");
}

or

@Override
protected void addToStringFields(final ToStringBuilder builder) {
    super.addToStringFields(builder);
    builder.auto(this);
}

配置文件增加 entity 路径(v3 和 v4)

  1. devlib/schematoollib/persistence.xml —— 脚本生成 sql 文用到(新增的 entity 需要添加到里面,然后执行 sql 脚本)
  2. numata/tools/META-INF/persistence.xml —— 单体测试用到

persistence.xml

调用脚本生成 SQL 文

  1. 对应 entity 的配置文件:devlib/schematoollib/persistence.xml

  2. 修改数据库:build.properties

  3. 脚本:build.xml - generateAddSchemaSql

  4. ant 脚本执行前,先 build 一下

  5. 生成:out/packages/schemqSql/addSchema.sql

  6. 筛选出 addSchema.sql 中本次新增的 entity 的 sql 文。将 sql 文脚本放入对应位置 sql/verified/3.15.04。

EntityLifecycle 作成

public interface ReleaseMenuLifecycle extends Lifecycle<ReleaseMenu> {  
    ImmutableList<ReleaseMenu> findBy(C4v4MenuId menuId, CenterId centerId);  
}

EntityLifecycleImpl 作成

public class ReleaseMenuLifecycleImpl extends AbstractManagementLifecycle<ReleaseMenu> implements ReleaseMenuLifecycle {

    public ReleaseMenuLifecycleImpl(final LifecycleContext context) {
        super(context);
    }

    @Override
    public ImmutableList<ReleaseMenu> findBy(final C4v4MenuId menuId, final CenterId centerId) {
        final QueryBuilderMulti<ReleaseMenu> builder = newMultipleResultQueryBuilder();

        builder.add("select o from ReleaseMenu o where 1=1");
        builder.add(" and o.centerId = :theCenterId ", centerId != null ? centerId.toString() : "", centerId != null);
        builder.add(" and o.menuId = :theMenuId ", menuId, menuId != null);

        return builder.getReadOnlyResult();
    }

    @Override
    public Class<ReleaseMenu> getEntityType() {
        return ReleaseMenu.class;
    }

    @Override
    public ReleaseMenu newInstance() {
        return new ReleaseMenu();
    }
}

EducationInstitute 与 EducationCenter

问题

  1. #Work/question addToStringFields 方法有什么用?builder.auto(this); 有什么用?
  2. entity 中,get、set 方法是否可以使用 final 修饰符?
    • 不需要

#总结 entity 双向关联时,OneToManySupport 的使用?

  1. #Work/question_delay @ReplicatorMapping(skip = true) 注解有啥用?定义双向关联时,是否必须加上?
  2. #Work/question_delay entityA 中设置了 manytoone 的关系,entityB 中一定需要设置 onetomany 的关系吗?
    1. 不一定需要设置,可以只由一方代码维护关系。只由一方维护时,不需要使用 OneToManySupport。entity 生成简单的 get 和 set 方法就行
    2. 什么时候需要两方维护???
  3. #Work/question_delay 使用 OneToManySupport 的作用是什么???
    1. 关联的 2 个 entity,在双方同事维护时,需要使用 OneToManySupport。

entitydata

作成规则:

  1. 变量
    1.

// 参照:

businessdata

// 参照:

entity 与 entitydata 转化(AbstractPersistenceOperationService)

V4

entity → entitydata

entity 作为参数,调用 entitydata 的 newInstance 方法。如下:

@ToStringAppendedProperty
public class ObservationRecordData extends AbstractRestBusinessData {

    static public ObservationRecordData newInstance(final RandomSeedSupplier randomSeedSupplier, final ObservationRecord observationRecord) {
        return new ObservationRecordData(randomSeedSupplier, observationRecord.getEntityId(),
                observationRecord.getLessonDailyScheduleTimeTable() == null ? observationRecord.getNoticeOfDate() : observationRecord.getLessonDailyScheduleTimeTable().getDate(),
                observationRecord.getContents(), observationRecord.getEntryDate(), Optional.ofNullablegetFullName).orElse(null);
    }

    public ObservationRecordData() {
        super();
    }

    public ObservationRecordData(final RandomSeedSupplier randomSeedSupplier, final EntityId entityId) {
        super(randomSeedSupplier, entityId);
    }

    public ObservationRecordData(final RandomSeedSupplier randomSeedSupplier, final String uid) {
        super(randomSeedSupplier, uid);
    }

    public ObservationRecordData(final RandomSeedSupplier randomSeedSupplier, final EntityId entityId, final LocalDate localDate, final String contents, final LocalDateTime entryDate,
            final String entryTeacherName) {
        super(randomSeedSupplier, entityId);
        this.dateWeek = localDate != null ? localDate.format(YYYYMDE) : "";
        this.contents = contents;
        this.entryDateLabel = entryDate != null ? entryDate.format(YYYYMD) : "";
        this.entryTeacherName = entryTeacherName;
    }
} 

entitydata → entity

final IntraSchoolGroup intraSchoolGroup = decodeResolve(IntraSchoolGroup.class, SchoolClassData::new, parameter.getClassUid());
final List<SchoolObservationTag> tagList = parameter.getTagList() == null ? Collections.emptyList()
                : parameter.getTagList().stream().map(o -> decodeResolve(SchoolObservationTag.class, SchoolObservationTagData::new, o)).collect(Collectors.toList());

V3

使用convertToValue (不一定要@CoverterTaget 注解)

final Teacher teacher = resolveCorrespondingEntityFor(teacherData, Teacher.class);
final TeacherData teacherData = convertToValue(teacher, TeacherData.class);
final List<Teacher> teacherList = teacherDataList.stream().map(o -> resolveCorrespondingEntityFor(o, Teacher.class)).collect(Collectors.toList());
final List<TeacherData> teacherDataList = convertToValueList(teacherList, TeacherData.class); 

 final List<TeacherData> teacherDataList = convertToValueList(teacherList, getConverterFactory().getConverterFor(TeacherData.class, Teacher.class)); 

 final List<TeacherData> teacherDataList = teacherList.stream().map(o -> convertToValue(o, TeacherData.class)).collect(Collectors.toList());

使用 getConverterFactory().getConverterFor 获取转换方法(没有 ConverterTarget 注解)

public List<SchoolAbsentReasonData> findBySchoolIdAndYear(final ServiceRequestContext seriveReContext) {
    final SchoolAbsentReasonLifecycle lifecycle = (SchoolAbsentReasonLifecycle) getLifecycleFactory().getLifecycleFor(SchoolAbsentReason.class);
    final List<SchoolAbsentReason> schoolReasons = lifecycle.findBySchoolAndYear(seriveReContext.getCorrespondingSchool().getSchoolId(), seriveReContext.getCorrespondingSchoolYear().getYear()
            .getYear());

    final Converter<SchoolAbsentReasonData, SchoolAbsentReason> converter =  getConverterFactory().getConverterFor (SchoolAbsentReasonData.class, SchoolAbsentReason.class);
    return  convertToValueList(schoolReasons, converter); 
}

private SchoolYearData findschoolYearData(final ServiceRequestContext seriveReContext, final int year) {
    final SchoolYearLifecycle lifecycle = (SchoolYearLifecycle) getLifecycleFactory().getLifecycleFor(SchoolYear.class);
    final SchoolYear entity = lifecycle.findBySchoolIdAndYear(seriveReContext.getCorrespondingSchool().getSchoolId(), year);
    final Converter<SchoolYearData, SchoolYear> converter =  getConverterFactory().getConverterFor (SchoolYearData.class, SchoolYear.class);
    final SchoolYearData data =  converter.createDataFrom(getConversionContext(), entity); 
    return data;
}

使用 entityData 的 newInstance 进行实例化

VacationApplicationData.newInstance

@ConverterMapping 注解作用?

  1. skipMapping
  2. referentTransient
  3. publicTargetOnly

newInstance 和 convertToValue 的区别?

答: 若 entityData 类加了注解@ConverterTarget(targetEntity = Teacher.class),可以使用 convertToValue

  1. 若是 entityData 中定义的属性 比 entity 少,entity 转化成 entityData 后,entityData 能使用未定义的属性吗?

    答: 不能,entityData 只能使用自己定义的属性。

  2. 何时使用 newInstance?何时使用 convertToValue?

@ManyToOne(cascade = { CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH }, fetch = FetchType.LAZY, optional = false)

@JoinColumn(name = "RATING_ENTITYID", nullable = false)

private PhysicalTestRating rating;